package com.xz.courseschedule.utils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: zys
 * @CreateTime: 2025-05-24
 */

//班级工具栏
public class ClassUtil {

    public static final Random RANDOM = new Random();

    //课程表最大节数，当前是24，用于生成随机时间的上限
    public static int MAX_WEEK_TIMESLOT = 24; //0~24，一周5天*每天课5大节

    /**
     * 用于切割获得编码的染色体中需要的属性
     *
     * @param aim 目标信息
     * @param source 源编码
     * @return 切割出来的目标信息
     *
     * 比如传入的source 是 CL123456TC789012CO345678ATTR01SW01EW01B1AN01CC1F1TS01RM123456
     * 那我们想要截取的是班级班号则传入 ConstantInfo.CLASS_NO 就会得到 CL123456
     */

    public static String cutGene(String aim, String source) {
        int startIndex = 0;
        int endIndex = 0;
        for (Map.Entry<String, Integer> entry : ConstantInfo.RSLES.entrySet()) {
            endIndex += entry.getValue();
            if (entry.getKey().equals(aim)) {
                if (endIndex > source.length()) {
                    return ""; // 防止越界
                }
                return source.substring(startIndex, endIndex);
            }
            startIndex += entry.getValue();
        }
        return "";
    }

    /**
     * 返回cutGene时Timeslot的startIndex
     * @return
     *
     * 如果找不到上课时间则把value值一直加，直到找到就可以找到起始位置了
     */
    public static int getTimeslotStartIndex(){
        int indexBeforeTimeslot = 0;
        for (Map.Entry<String,Integer> entry:ConstantInfo.RSLES.entrySet()){
            if (entry.getKey().equals(ConstantInfo.TIMESLOT)){
                return indexBeforeTimeslot;
            }
            indexBeforeTimeslot += entry.getValue();
        }
        return indexBeforeTimeslot;
    }

    /**
     * 随机时间
     * @return -> 俩位时间
     *
     * 随机生成1-25数字，用于定义在哪一节课
     */
    public static String randomTime(){
        int temp = RANDOM.nextInt(MAX_WEEK_TIMESLOT) +1;
        return temp < 10 ? ("0"+temp) :String.valueOf(temp);
    }

    /**
     * 生成 00 - 24 的时间集合
     */
    public static List<String> getAllTime(){
        List<String> timeList = new ArrayList<>();
        for (int i = 0; i <= MAX_WEEK_TIMESLOT; i++) {
            if (i < 10) {
                timeList.add("0" + i);
            } else {
                timeList.add(String.valueOf(i));
            }
        }
        return timeList;
    }

    /**
     * 解决同一个class同时有两个timeslot在上课的冲突问题
     * @param gene 当前发生冲突的基因编码
     * @param geneList 种群
     * @param classNo 班级
     * @param teacherNo 讲师编号
     * @param classTime 上课时间
     * @return 未使用的时间
     **/
    public static String randomTimeForClassConflict(String gene,List<String> geneList,String classNo,String teacherNo,String classTime){
        //找出当前班级在01-25时间之间还未使用的时间
        Set<String> usedTimeList = geneList.stream()
                .filter(item -> cutGene(ConstantInfo.CLASS_NO,item).equals(classNo))
                .map(item -> cutGene(ConstantInfo.TIMESLOT,item))
                .collect(Collectors.toSet());
        System.out.println(classNo+" 班级 剩余空闲上课时间 "+usedTimeList);
        return getFreeTime(usedTimeList);
    }

    public static String randomTimeForTeacherConflict(String gene,List<String> geneList,String teacherNo,String classNo){
        //找出当前教室在01-25时间之间还未使用的时间
        // usedTimeList 存储了该教师已经使用的所有时间段
        Set<String> usedTimeList = geneList.stream()
                .filter(item -> cutGene(ConstantInfo.TEACHER_NO,item).equals(teacherNo))
                .map(item->cutGene(ConstantInfo.TIMESLOT,item))
                .collect(Collectors.toSet());
        System.out.println(teacherNo+" 教师 已经用的上课时间 "+usedTimeList);
        return getFreeTime(usedTimeList);
    }

    /**
     * 获取 01-25 内还未使用的时间
     *
     * 找出一个没有被当前班级或教师占用的时间点；
     * 如果有的话，就随机返回一个；
     * 如果没有，就“硬着头皮”返回一个随机时间（可能会导致冲突）。
     **/
    private static String getFreeTime(Set<String> usedTimeList) {
        List<String> allTime = getAllTime();

        boolean isRemoveSuccess = allTime.removeAll(usedTimeList);

        if (isRemoveSuccess && !allTime.isEmpty()){
            int randomIndex = RANDOM.nextInt(allTime.size());
            return allTime.get(randomIndex);
        }

        return randomTime();
    }

    /**
     * 计算每个个体的适应值
     * 目的:进行软约束
     */
//    public static double fitness(List<String> individualList){
//        double K1 = 0.3;//权重1 - 不是早八
//        double k2 = 0.7;//权重2 - 不是晚课
//        int F1 = 0;
//        int F2 = 0;
//        double FX = 0;//总体适应度
//        //计算每一个个体的适应度
//        for (String gene:individualList){
//            int timeslot = Integer.parseInt(cutGene(ConstantInfo.TIMESLOT,gene));//从编码中获取上课时间
//            boolean isEarlyMorning = timeslot % 5 == 0;//判断如果是等于0则代表是早八
//            boolean isLateNight = timeslot%5 == 4;//如果余数等于4则代表是晚课
//            if (!isEarlyMorning) F1++;
//            if (!isLateNight) F2++;
//        }
//        FX = K1 * F1 + k2 * F2;
//        return FX;
//    }
    public static double fitness(List<String> individualList){
        double K1 = 0.3; // 权重1 - 不安排早八
        double K2 = 0.7; // 权重2 - 不安排晚课
        int F1 = 0;
        int F2 = 0;
        double FX = 0;

        for (String gene : individualList) {
            int timeslot = Integer.parseInt(cutGene(ConstantInfo.TIMESLOT, gene));
            boolean isEarlyMorning = timeslot % 5 == 1; // 早八
            boolean isLateNight = timeslot % 5 == 0;   // 晚课

            if (!isEarlyMorning) F1++; // 非早八加分
            if (!isLateNight) F2++;    // 非晚课加分
        }

        FX = K1 * F1 + K2 * F2;
        return FX;
    }



}
